package com.dd.common.aspect;

import com.dd.common.aspect.annotation.MethodLog;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * 方法执行时间监控切面
 * 记录方法执行耗时，超时则打印 WARN 日志。
 * 注意：这和 http 层面耗时不同，这里是方法层面耗时。
 */
@Aspect
@Order(99) // 优先级低于事务等核心切面
@Component
@Slf4j
public class MethodTimeMonitorAspect {

    // 默认超时阈值（毫秒）
    private static final long DEFAULT_TIMEOUT_THRESHOLD = 1000L;

    @Around("execution(* com.dd.*.controller..*.*(..)) || " +
            "@annotation(com.dd.common.aspect.annotation.MethodLog)")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();

        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();

        // 获取类名和方法名
        String className = method.getDeclaringClass().getSimpleName();
        String methodName = method.getName();
        String fullMethod = className + "." + methodName;

        // 获取注解中的描述和超时设置
        MethodLog methodLog = method.getAnnotation(MethodLog.class);
        String description = methodLog != null ? methodLog.value() : "";
        long timeoutThreshold = methodLog != null ? methodLog.timeout() : DEFAULT_TIMEOUT_THRESHOLD;

        String desc = description.isEmpty() ? fullMethod : description;

        try {
            Object result = joinPoint.proceed();
            long duration = System.currentTimeMillis() - startTime;

            // 正常返回日志
            if (duration >= timeoutThreshold) {
                log.warn("[性能监控] 方法: {}, 耗时: {}ms (⚠️ 超时)", desc, duration);
            } else {
                log.debug("[性能监控] 方法: {}, 耗时: {}ms", desc, duration);
            }

            return result;

        } catch (Throwable e) {
            long duration = System.currentTimeMillis() - startTime;
            log.error("[性能监控] 方法: {}, 执行异常, 耗时: {}ms, 异常: {}",
                    desc, duration, e.getMessage());
            throw e;
        }
    }
}